#ifndef SWAP_H_
#define SWAP_H_

#include <stdbool.h>
#include "vehicleState.h"
#include "operations.h"
#include "tabooList.h"
#include "solution.h"
#include "los.h"
#include "graph.h"

/**un possibile valore di ritorno della funzione isTQOKSwap*/
#define SWAP_NOTQ_OK 0
/**un possibile valore di ritorno della funzione isTQOKSwap*/
#define SWAP_ONLYEDGE1 1
/**un possibile valore di ritorno della funzione isTQOKSwap*/
#define SWAP_ONLYEDGE2 2
/**un possibile valore di ritorno della funzione isTQOKSwap*/
#define SWAP_BOTHEDGES 3

/** Numero di iterazioni di tenure per gli archi aggiunti nella mossa SWAP. */
#define SWAP_ADDTENURE 2
/** Numero di iterazioni di tenure per gli archi rimossi nella mossa SWAP. */
#define SWAP_REMTENURE 1
/**indica una modalita' per generare lo swap di 2 archi. Da utilizzare nella funzione generateCrossedEdges
 * */
#define SWAP_GENERATIONMODE_0 0
/**indica una modalita' per generare lo swap di 2 archi. Da utilizzare nella funzione generateCrossedEdges
 * */
#define SWAP_GENERATIONMODE_1 1

/**TODO modificare questa definizione. Difatti l'arco triangolante su nodi già nel percorso non aggiunge dei nodi al totale
 * il file racchiude tutte le funzioni, le variabili e i simboli usati per gestire la mossa Add. Come da manuale, una mossa viene definita add(n)
 * se aggiunge alla soluzione originale n numero di nodi (eventualmente mai attraversati dalla soluzione). L'add qui implementato e' l'add(1) cioe' l'inclusione
 * di un singolo nodo nella soluzione. L'inclusione di un solo nodo genera in realta' 3 sottocasi:
 * 1) l'eliminazione di un arco e l'inclusione di 2
 * 2) l'inclusione di 2 archi da un nodo di inizio
 * 3) l'inclusione di 2 archi da un nodo di fine
 * Per ulteriori informazioni riguardo l'add, vedere il manuale.
 */

/* Struttura usata principalmente per prototipi più maneggevoli. */
typedef struct SwapBestChoice {
	/**uno dei 2 archi selezionati da swap il cui swappamento comporta il miglior aumento di profitto conforme alla taboo List finora trovato*/
	EdgeID bestRemove1;
	/**uno dei 2 archi selezionati da swap il cui swappamento comporta il miglior aumento di profitto conforme alla taboo List finora trovato*/
	EdgeID bestRemove2;
	EdgeID bestAdd1;
	EdgeID bestAdd2;
	bool useAdd1;
	bool useAdd2;
	/**valore della funzione obiettivo qualora si effettuasse lo swap di bestEdge1 e bestEdge2*/
	int bestValutation;
} SwapBestChoice;

/** puntatore di servizio.*/
typedef SwapBestChoice* PswapBestChoice;

/**costruisce una nuova struttura dati utilizzabile per contenere dati temporanei circa
 * gli archi da coinvolgere in swap per ottenere la migliore soluzione. i dati temporanei
 * vengono <b>tutti</b> settati a zero. La struttura deve essere usata all'interno di swap per
 * contenere quali sono, fino a quel momento, gli archi migliori da coinvolgere
 *
 * @return un'istanza di SwapBestChoice
 */
PswapBestChoice initSwapBestChoice();

/**genera una possibile coppia di archi swappati. Dati due archi da swappare esistono 2 modi diversi per effettuare lo swap; il
 * parametro generationmode si occupa infatti di scegliere quali tipo di coppia di archi swappati generare
 * \dot
 * 	digraph G {
 *		a -> b [dir=none ]
 *		c -> d [dir=none ]
 *		a -> c [dir=none color="red"]
 *		b -> d [dir=none color="red"]
 *		a -> d [dir=none color="blue"]
 *		b -> c [dir=none color="blue"]
 * }
 * \enddot
 *
 * \pre
 *  \li e1,e2 non NULL
 *  \li s1 e s2 devono essere stati inizializzati
 * \post
 *  \li i puntatori s1 e s2 puntano a due istanza di EdgeID corrispondenti agli archi swappati
 *  \li gli EdgeID contenuti in s1 e s2 sono validati
 *
 * @param e1 l'arco da swappare
 * @param e2 l'arco da swappaer
 * @param s1 un arco swappato
 * @param s2 un arcop swappato
 * @param generationmode quale coppia di archi swappati generare
 */
void generateCrossedEdges(PedgeID e1, PedgeID e2,PedgeID s1,PedgeID s2,int generationmode);

/**stampa la serie di dati temporanei
 *
 * \pre
 *  \li f non NULL
 *  \li obj non NULL
 *
 * @param f il file su cui stampare
 * @param obj i dati temporanei da stampare
 */
void printSwapBestChoice(FILE* f,PswapBestChoice obj);

/**libera dalla memoria tutti i file temporanei contenuti in obj, non lasciando alcuna traccia
 *
 * \post
 *  la memoria e' libera dalla vecchia istanza di obj
 * @param obj l'istanza da eliminare
 */
void freeSwapBestChoice(PswapBestChoice obj);

/**computa l'intorno della soluzione tramite un intorno add e ricava il migliore stato possibile per il veicolo
 *
 * @param graph indica il grafo su cui computare il nuovo intorno. Non inserire valore NULL
 * @param now è l'iterazione STM corrente, usata per approciarsi alla taboolist.
 * @param vehicleState indica lo stato di un veicolo, utilizzato come centro dell'intorno. Non inserire valore NULL.
 * 			Attenzione: questo stato, a meno che la mossa fallisca (supponiamo possa fallire per mille motivi) sarà MODIFICATO.
 * @param k l'identificativo del veicolo interessato all'ADD. Richiesto nel confronto sulla matrice G.
 * @param tabooList indica la tabulist che include alcuni divieti su alcuni archi. Non inserire valore NULL
 * @param notWorseningMoves filtra i candidati sui soli che non peggiorano il profitto. TODO da implementare ancora in SWAP.C
 * @return MOVE_STATUS_OK sse una mossa viene effettivamente eseguita; MOVE_STATUS_FAIL altrimenti.
 */
int solveSwapNeighbourhood(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now, pLOSConfiguration pLOSconfig, bool notWorseningMoves);

/**effettua la mossa modificando per sempre la struttura pvs passata per riferimento
 *
 * \pre
 *  \li pg, pvs, pgm, ptl e pbest non devono essere NULL
 * \post
 *  \li la struttura pvs passa una volta in meno dagli archi specificati da pbest (oppure non ci passa affatto)
 *  \li la struttura pvs passa una colta in piu' negli archi specificat da pbest
 *  \li la struttura pgm viene modificata
 *  \li la taboo list contiene nuovi taboo
 *
 * @param pg il grafo su cui sussiste la soluzione
 * @param pvs lo stato di questo particolare camion
 * @param pgm la matrice dei soddisfacimenti da modificare
 * @param k il camion considerato
 * @param ptl la taboo list da aggiornare
 * @param now l'iteraizone attuale in cui avviene la modifica
 * @param pbest la struttura contenente il miglior set di archi finora trovati
 */
void makeSwapMove(Pgraph pg,PvehicleState pvs, PGMatrix pgm, int k, PtabooList ptl, TabooExpire now, PswapBestChoice pbest, int addTenure, int removeTenure);

/**aggiorna una struttura PswapBestChoice con dei valori piu' aggiornati
 *
 * \pre
 *  \li pbc non NULL
 *  \li toadd1, toadd2, toremove1, toremove2 non NULL e con i<j
 *
 * @param pbc indica la struttura da aggiornare
 * @param toadd1 indica il primo arco da aggiungere alla soluzione
 * @param toadd2 indica il secondo arco da aggiungere alla soluzione
 * @param toremove1 indica il primo arco da rimuovere dalla soluzione
 * @param toremove2 indica il secondo arco da rimuovere dalla soluzione
 * @param jk indica il profitto ottenuto aggiungendo e rimuovendo questi archi
 * @param gtoadd1 se TRUE impone di soddisfare il primo arco da aggiungere
 * @param gtoadd2 se TRUE impone di soddisfare il secondo arco da aggiungere
 */
void updateSwapBestChoice(PswapBestChoice pbc, PedgeID toadd1, PedgeID toadd2,PedgeID toremove1,PedgeID toremove2, int jk,bool gtoadd1,bool gtoadd2);

/**verifica se il percorso ottenuto:
 * \li considerando il cammino in state
 * \li considerando gli archi toadd1 e toadd2
 * \li tralascando gli archi toremove1 e toremove2
 *
 * e' compatibile con la condizione TQOK
 *
 * \pre
 *  \li graph non NULL
 *  \li state non NULL
 *  \li pgm non NULL
 *  \li gli edgeID non sono NULL
 *  \li k compreso in [0;K[
 *
 * @param state indica lo stato corrente della soluzione di un veicolo
 * @param toadd1 indica un edge da aggiungere
 * @param toadd2 indica un edge da aggiungere
 * @param toremove1 indica un edge da togliere
 * @param toremove1passed indica quante volte il camion passa per l'arco toremove1
 * @param toremove2 indica un edge da togliere
 * @param toremove2passed indica quante volte il camion passa per l'arco toremove2
 * @return uno dei possibili valori:
 * 	\li SWAP_NOT_TQOK se il vincolo di tempo o di capacita' non viene soddisfatto
 * 	\li SWAP_ONLYEDGE1 se e' TQOK ma solo toadd1 puo' essere soddisfatto (mentre toadd2 viene solo percorso)
 * 	\li SWAP_ONLYEDGE2 se e' TQOK ma solo toadd2 puo' essere soddisfatto (mentre toadd1 viene solo percorso)
 * 	\li SWAP_BOTHEDGES se e' TQOK ed entrambi gli archi toadd1 e toadd2 vengono soddisfatti
 */
int isTQOKSwap(Pgraph graph,PGMatrix pgm,int k,PvehicleState state,PedgeID toadd1, PedgeID toadd2, PedgeID toremove1,int toremove1passed, PedgeID toremove2,int toremove2passed);

#endif /* SWAP_H_ */
